package fmi.chesstern.pieces;

import java.util.HashSet;
import java.util.Set;


import fmi.chesstern.game.BoardField;
import fmi.chesstern.game.GameBoardState;
import fmi.chesstern.game.Move;
import fmi.chesstern.game.MutableGameBoardState;
import fmi.chesstern.pieces.strategy.BishopStrategy;
import fmi.chesstern.pieces.strategy.ChessPieceStrategy;
import fmi.chesstern.pieces.strategy.KingStrategy;
import fmi.chesstern.pieces.strategy.KnightStrategy;
import fmi.chesstern.pieces.strategy.PawnStrategy;
import fmi.chesstern.pieces.strategy.QueenStrategy;
import fmi.chesstern.pieces.strategy.RookStrategy;

public enum ChessPieceType {
	BISHOP(new BishopStrategy()),
	KING(new KingStrategy()),
	KNIGHT(new KnightStrategy()),
	PAWN(new PawnStrategy()),
	QUEEN(new QueenStrategy()),
	ROOK(new RookStrategy());
	
	private ChessPieceStrategy pieceStrategy;
	
	private ChessPieceType(ChessPieceStrategy pieceStrategy) {
		this.pieceStrategy = pieceStrategy;
	}
	
	public Set<Move> getValidMoves(GameBoardState board, BoardField currentPosition) {
		if (board.getCurrentPlayer() != board.getPieceAt(currentPosition).getColor()) {
			return new HashSet<Move>();
		}
		
		Set<Move> result = new HashSet<Move>();
		
		Set<BoardField> validNewPositions = pieceStrategy.getValidNewPositions(board, currentPosition);
		
		// filters moves that put the king in danger
		filterValidMoves:
		for (BoardField validNewPosition : validNewPositions) {
			Move move = new Move(currentPosition, validNewPosition);
			
			MutableGameBoardState nextBoard = new MutableGameBoardState(board);
			
			nextBoard.makeMove(move);
			
			for (BoardField field : nextBoard.getPlayerFields(nextBoard.getCurrentPlayer())) {
				ChessPiece chessPiece = nextBoard.getPieceAt(field);
				
				if (chessPiece.getType().pieceStrategy.getValidNewPositions(nextBoard, field).contains(
						nextBoard.getKingPositionOf(board.getCurrentPlayer()))) {
					continue filterValidMoves;
				}
			}
			
			result.add(move);
		}
		
		return result;
	}
}
